#ifndef ALGORITHM_PERMUTATION__
#define ALGORITHM_PERMUTATION__

#include <map>
#include <list>
#include <algorithm>
#include <iostream>
#include <sstream>
#include <iomanip>

#include "algorithm.h"
#include "area.h"
#include "options_genetic.h"
#include "call_list.h"

/** Informace o cyklech v permutaci vysilacu pro cyklicky crossover.
 */
class PermutationInfo { /* holds the positions of the index */
public:
	/** Defaultni konstruktor.
	 */
	PermutationInfo(): size(0) {}
	/** Destruktor.
	 */
	~PermutationInfo() {
		if (size != 0) {
			delete[] position;
			delete[] cycle_index;
		}
	}
	bool Empty(int index);
	void Initialize(int size);
	void Load(int * permutation);
	bool Odd(int index);
	void Set(int value, int cycle);
	int * position; ///< indexy pozice jednotlivych vysilacu v prvnim chromozomu
	int * cycle_index; ///< indexy jednotlivych cyklu
	int size; ///< pocet vysilacu
};

/** Pomocna struktura pro ulozeni poradi reseni. Pamatuje si vsechny reseni, ktera jsou na stejne pozici.
 */
class RankInfo {
public:
	/** Defaultni konstruktor.
	 */
	RankInfo() {
		rank = 0;
		positions.clear();
	}
	int rank; ///< poradi
	std::list<int> positions; ///< indexy reseni v cele populaci, ktere jsou umistene na tomto poradi
};

/** Permutacni geneticky algoritmus. Pracuje s resenimi ve forme poradi vysilacu (permutace) pro
 * vstup do sekvencniho algoritmu.
 */
class PermutationAlgorithm: public Algorithm {
public:
	/** Defaultni konstruktor permutacniho algoritmu.
	 * \param o nastaveni permutacniho algoritmu
	 */
	PermutationAlgorithm(Options * o):options((GeneticOptions *)o), Algorithm(o) {};
	/** Konstruktor rovnou prirazujici i mapu se zadanim.
	 * \param a mapa zadani
	 * \param o nastaveni permutacniho algoritmu
	 */
	PermutationAlgorithm(Area * a, Options * o): Algorithm(o), options((GeneticOptions *)o) {
		Set(a);
	}
	/** Nastaveni mapy a inicializace pomocnych datovych struktur.
	 * \param a mapa zadani
	 */
	void Set(Area * a) {
		area = a;
		perm_info.Initialize(a->size);
	}
	virtual bool Solve();
	/** Vypise do logu nastaveni genetickeho algoritmu.
	 */
	virtual void PrintInfo() {
		options->Log() << "Geneticky algoritmus zalozeny na permutacich skladajici se ze 3 casti: \r\n - nahodna tvorba pocatecnich genu (permutace vysilacu) \r\n - setrizeni prvotni generace \r\n - beh genetickeho algoritmu" << std::endl;
	}
	/** Vrati popis nastaveni algoritmu.
	 * \return popis nastaveni
	 */
	std::string GetDetail() {
		return "permutation: " + options->GetTitle(true);
	}
	void PrintGeneration(int ** generation, int size);
private:
	void Genetic();
	void CrossOver(int * p1, int * p2, int * child);
	void Mutate(int * individual);
	int ChooseSecondParent();
	void CountRanks();
	void ChangeRank(int from, int to, int index);
	void PrintRanks();
	void Generate();
	int * MixArray(int * a);
	int AssignFrequencies(int * call_list);
	int GSD(int * call_list, GSDCallList & info);
	GeneticOptions * options; ///< nastaveni permutacniho algoritmu
	PermutationInfo perm_info; ///< infomace o permutacnich cyklech
	int ** generation; ///< pole se vsemi aktualnimi resenimi
	int best, ///< index nejlepsiho reseni
		best_span; ///< sirka frekvencniho pasma nejlepsiho reseni
	int sum_ranks; ///< soucet poradi vsech reseni
	RankInfo * ranks; ///< poradi vsech reseni algoritmu
};

#endif
